package com.work.demo.file;

import cn.hutool.core.io.FileUtil;

import java.io.*;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class FileUtils {


	/**
	 * 指定每一份文件的边界写入不同的文件中
	 *
	 * @param file  源文件
	 * @param index 文件顺序标识
	 * @param begin 开始指针的位置
	 * @param end   结束指针的位置
	 * @return long 文件指针
	 */
	private static long getWrite(String file, int index, long begin, long end) {

		long endPointer = 0L;

		try {
			//声明切割文件磁盘空间
			RandomAccessFile in = new RandomAccessFile(new File(file), "r");
			//定义一个可读可写并且后缀名为.tmp二进制的临时文件
			RandomAccessFile out = new RandomAccessFile(file + "_" + index + ".tmp", "rw");
			//声明具体每一个文件字节数组为1024
			byte[] b = new byte[1024];
			//从指定文件读取字节流
			in.seek(begin);
			int n = 0;
			while (in.getFilePointer() <= end && (n = in.read(b)) != -1) {
				out.write(b, 0, n);  //写入不同的二进制文件
			}

			//定义当前读取文件指针
			endPointer = in.getFilePointer();
			//关闭输入流
			in.close();
			//关闭输出流
			out.close();
		} catch (Exception e) {
			e.printStackTrace();
		}

		return endPointer;
	}

	/**
	 * 文件切片
	 *
	 * @param file  需要被切割的源文件
	 * @param count 切割文件的个数
	 */
	private static void getSplitFile(String file, int count) {
		try {
			//预分配文件占用磁盘空间“r”表示只读的方式“rw”支持文件随机读取和写入
			RandomAccessFile raf = new RandomAccessFile(new File(file), "r");
			//文件长度
			long length = raf.length();
			//计算切片后，每一文件的大小
			long maxSize = length / count;
			//定义初始文件偏移量（读取文件进度）
			long offset = 0L;
			//开始切割
			for (int i = 0; i < count - 1; i++) { //count-1 其中的一份文件不处理
				//初始化
				long fbegin = offset;
				//分割第几份文件
				long fend = (i + 1) * maxSize;
				//写入二进制临时文件中
				offset = getWrite(file, i, fbegin, fend);
			}

			//将剩余的写入到最后一份文件中
			if ((int) (length - offset) > 0) {
				getWrite(file, count - 1, offset, length);
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void main(String[] args) {
		String filePath = "C:\\Users\\admin\\Documents\\WXWork\\1688851079825408\\Cache\\File\\2021-11\\40万80f_x.csv";
		String imgPath = "C:\\Users\\admin\\Desktop\\微信图片_20211201172845.png";
		int count = 8;
		//文件切片
//		getSplitFile(filePath, count );
		//合并文件
		//merge(filePath, filePath, count);
//		File file = FileUtil.file(filePath);
//		try {
//			String s = md5HashCode(file);
//			System.out.println(s);
//		} catch (FileNotFoundException e) {
//			e.printStackTrace();
//		}
		File file = FileUtil.file(filePath);
		try {
			FileInputStream fis = new FileInputStream(file);
//			FileInputStream fis1 = new FileInputStream(imgPath);
			int available = fis.available();
//			int available1 = fis1.available();
			byte[] byte1 = new byte[fis.available()];
			byte[] byte2 = new byte[fis.available()];
			int read = fis.read(byte1, 0, 10485760);
			System.out.println(read);
			int read2 = fis.read(byte2, 26 * 10485760, 282051030 - 26 * 10485760);
			System.out.println(read2);
			System.out.println(282051030 - 272629760);
			fis.close();

// 			fis1.read(byte2,0,available1);
//			InputStream inputStream = new ByteArrayInputStream(bytes);
//			byte[] bytes3 = byteMerger(byte1, byte2);
//			byteHashcode(bytes3,"MD5");


		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	/**
	 * 合并文件
	 *
	 * @param file     指定合并后的文件
	 * @param tempFile 分割前的文件名
	 * @param temCount 文件的个数
	 */
	private static void merge(String file, String tempFile, int temCount) {
		RandomAccessFile raf = null;
		try {
			// 声明随机可读可写的文件
			raf = new RandomAccessFile(new File(file), "rw");
			// 开始合并文件，对应切片的二进制文件
			for (int i = 0; i < temCount; i++) {
				RandomAccessFile reader = new RandomAccessFile(
								new File(tempFile + "_" + i + ".tmp"), "r");
				byte[] b = new byte[1024];
				int n = 0;
				while ((n = reader.read(b)) != -1) {
					raf.write(b, 0, n);
				}
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				raf.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}


	/**
	 * java获取文件的md5值
	 *
	 * @param fis 输入流
	 * @return
	 */
	public static String md5HashCode(InputStream fis) {
		try {
			//拿到一个MD5转换器,如果想使用SHA-1或SHA-256，则传入SHA-1,SHA-256
			MessageDigest md = MessageDigest.getInstance("MD5");

			//分多次将一个文件读入，对于大型文件而言，比较推荐这种方式，占用内存比较少。
			byte[] buffer = new byte[1024];
			int length = -1;
			while ((length = fis.read(buffer, 0, 1024)) != -1) {
				md.update(buffer, 0, length);
			}
			fis.close();
			//转换并返回包含16个元素字节数组,返回数值范围为-128到127
			byte[] md5Bytes = md.digest();
			//1代表绝对值
			BigInteger bigInt = new BigInteger(1, md5Bytes);
			//转换为16进制
			return bigInt.toString(16);
		} catch (Exception e) {
			e.printStackTrace();
			return "";
		}
	}

	/**
	 * 获取文件的md5值 ，有可能不是32位
	 *
	 * @param file 文件
	 * @return
	 * @throws FileNotFoundException
	 */
	public static String md5HashCode(File file) throws FileNotFoundException {
		FileInputStream fis = new FileInputStream(file);
		return md5HashCode(fis);
	}


	/**
	 * 将文件转换成byte数组
	 *
	 * @param filePath 文件File类 通过new File(文件路径)
	 * @return byte数组
	 */
	public static byte[] File2byte(File filePath) {
		byte[] buffer = null;
		try {
			FileInputStream fis = new FileInputStream(filePath);
			ByteArrayOutputStream bos = new ByteArrayOutputStream();
			byte[] b = new byte[1024];
			int n;
			while ((n = fis.read(b)) != -1) {
				bos.write(b, 0, n);
			}
			fis.close();
			bos.close();
			buffer = bos.toByteArray();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return buffer;
	}


	// 使用ArrayList方法
//java 合并两个byte数组
	private static byte[] byteMerger(byte[] byte1, byte[] byte2) {
		byte[] byte3 = new byte[byte1.length + byte2.length];
		System.arraycopy(byte1, 0, byte3, 0, byte1.length);
		System.arraycopy(byte2, 0, byte3, byte1.length, byte2.length);
		return byte3;
	}

	public static String byteHashcode(byte[] bytes, String hashMethod) throws NoSuchAlgorithmException {
		/*
		 * MD5，Message Digest Algorithm 5，是一种被广泛使用的信息摘要算法，
		 * 可以将给定的任意长度数据通过一定的算法计算得出一个 128 位固定长度的散列值
		 */

		// 第一步，获取MessageDigest对象，参数为MD5字符串，表示这是一个MD5算法
		MessageDigest md5 = MessageDigest.getInstance(hashMethod);

		// 第二步，输入源数据，参数类型为byte[]
		md5.update(bytes);

		// 第三步，计算MD5值
		// String resultArray = md5.digest().toString();
		/*
		 * digest() 方法返回值是一个字节数组类型的 16 位长度的哈希值，通常，我们会
		 * 转化为十六进制的 32 位长度的字符串来使用，可以利用 BigInteger 类来做这个转化：
		 */

		BigInteger bigInt = new BigInteger(1, md5.digest());
		String resultStr = bigInt.toString(16);

		System.out.print("123的MD5为：");
		System.out.println(resultStr);
		System.out.println(resultStr.length());
		return resultStr;
	}
}
